﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;

using DataModel.Models;
using DataModel.Managers.SubManage;

namespace DataModel.Managers
{
    public class ScheduleManager
    {
        private UniversityPortalEntities entityModel;

        public ScheduleManager()
        {
            entityModel = new UniversityPortalEntities();
        }

        public ScheduleManager(UniversityPortalEntities entityModel)
        {
            this.entityModel = entityModel;
        }

        #region GetInformationForSchedule

        /// <summary>
        /// get lessons by group
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <returns></returns>
        public IQueryable<Lesson> GetLessonsByGroup(Int64 groupNumber)
        {
           return from l in entityModel.Lessons
                                      where l.Groups.FirstOrDefault(g => g.number == groupNumber) != null
                                      orderby l.beginTime
                                      select l;
        }

        /// <summary>
        /// Get lessons by group in semester
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <param name="semester"></param>
        /// <returns></returns>
        public IQueryable<Lesson> GetLessonsByGroup(Int64 groupNumber,int semester)
        {
            return from l in entityModel.Lessons
                   where (l.semester == semester && l.Groups.FirstOrDefault(g => g.number == groupNumber) != null)
                   orderby l.beginTime
                   select l;
        }

        /// <summary>
        /// Get All Subject by Group
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <returns></returns>
        public IQueryable<Subject> GetSubjectsByGroup(Int64 groupNumber)
        {
            var currentGroupLessons = this.GetLessonsByGroup(groupNumber);

            return from s in entityModel.Subjects
                   from l in currentGroupLessons
                   where s.ID == l.subjectID
                   select s;
        }

        /// <summary>
        /// Get subject by group in semester
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <param name="semester"></param>
        /// <returns></returns>
        public IQueryable<Subject> GetSubjectsByGroup(Int64 groupNumber,int semester)
        {
            var currentGroupLessons = this.GetLessonsByGroup(groupNumber,semester);

            return from s in entityModel.Subjects
                   from l in currentGroupLessons
                   where s.ID == l.subjectID
                   select s;
        }

        /// <summary>
        /// Get Schedule by group on DateBegin to DateEnd
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public ScheduleModel GetScheduleByGroup(Int64 groupNumber, DateTime begin, DateTime end)
        {
            var lessons = this.GetLessonsByGroup(groupNumber);
            ScheduleModel scheduleModel = new ScheduleModel(new List<DayModel>());

            bool saveTriggerByDay = false;

            while (begin <= end) 
            {
                var dayModel = new DayModel(new List<LessonModel>(), begin);

                foreach (var lesson in lessons)
                {
                    if (LessonInDate(begin, lesson))
                    {
                        LessonModel lm = new LessonModel();
                        lm.lessonID = lesson.ID;
                        lm.beginTime = lesson.beginTime;
                        lm.endTime = lesson.endTime;
                        lm.subject = entityModel.Subjects.FirstOrDefault(s => s.ID == lesson.subjectID);
                        lm.professor = entityModel.Professors.FirstOrDefault(p => p.ID == lesson.professorID);
                        lm.auditory = entityModel.Auditories.FirstOrDefault(a => a.ID == lesson.auditoryID);
                        lm.lessonType = entityModel.LessonTypes.FirstOrDefault(lt => lt.ID == lesson.lessonTypeID);
                        dayModel.lessonModels.Add(lm);
                        saveTriggerByDay = true;
                    }
                }

                if (saveTriggerByDay == true) scheduleModel.dayModels.Add(dayModel);

                begin = begin.AddDays(1);
                saveTriggerByDay = false;
            } 

            return scheduleModel;
        }

        /// <summary>
        /// Get Schedule By group in sem
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <param name="semester"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public ScheduleModel GetScheduleByGroup(Int64 groupNumber,int semester, DateTime begin, DateTime end)
        {
            var lessons = this.GetLessonsByGroup(groupNumber,semester);
            ScheduleModel scheduleModel = new ScheduleModel(new List<DayModel>());

            bool saveTriggerByDay = false;

            while (begin <= end)
            {
                var dayModel = new DayModel(new List<LessonModel>(), begin);

                foreach (var lesson in lessons)
                {
                    if (LessonInDate(begin, lesson))
                    {
                        LessonModel lm = new LessonModel();
                        lm.lessonID = lesson.ID;
                        lm.beginTime = lesson.beginTime;
                        lm.endTime = lesson.endTime;
                        lm.subject = entityModel.Subjects.FirstOrDefault(s => s.ID == lesson.subjectID);
                        lm.professor = entityModel.Professors.FirstOrDefault(p => p.ID == lesson.professorID);
                        lm.auditory = entityModel.Auditories.FirstOrDefault(a => a.ID == lesson.auditoryID);
                        lm.lessonType = entityModel.LessonTypes.FirstOrDefault(lt => lt.ID == lesson.lessonTypeID);
                        dayModel.lessonModels.Add(lm);
                        saveTriggerByDay = true;
                    }
                }

                if(saveTriggerByDay == true) scheduleModel.dayModels.Add(dayModel);

                begin = begin.AddDays(1);
                saveTriggerByDay = false;
            }

            return scheduleModel;
        }

        /// <summary>
        /// Hard Code
        /// </summary>
        /// <param name="date"></param>
        /// <param name="lesson"></param>
        /// <returns></returns>
        protected bool LessonInDate(DateTime date, Lesson lesson)
        {
            if (lesson.weekDay != date.DayOfWeek.ParseDayOfWeek() && ((lesson.beginDate > date) || (date > lesson.endDate)))
                return false;

            if (lesson.periodicity == 0)
            {
                    return true;
            }

            int bitOfMask = (WeekHelper.GetStudyWeekNumber(date)%lesson.periodicity)-1;
            int testParam = 1 << bitOfMask;

            return ((lesson.periodicityMask & testParam) != 0) ? true : false;
        }

        #endregion

        #region EditSchedule

        public void ChangeLessonData(Lesson lesson)
        {
            Lesson changingLesson = entityModel.Lessons.FirstOrDefault(l => l.ID == lesson.ID);
            if (changingLesson == null) throw new NullReferenceException("Changing lesson is not found");

            //shallow copy of object's changes
            changingLesson.Auditory = lesson.Auditory;
            changingLesson.auditoryID = lesson.auditoryID;
            changingLesson.AuditoryReference = lesson.AuditoryReference;
            changingLesson.beginDate = lesson.beginDate;
            changingLesson.beginTime = lesson.beginTime;
            changingLesson.endDate = lesson.endDate;
            changingLesson.endTime = lesson.endTime;
            changingLesson.EntityKey = lesson.EntityKey;
            changingLesson.Groups = lesson.Groups;
            changingLesson.JournalCells = lesson.JournalCells;
            changingLesson.LessonType = lesson.LessonType;
            changingLesson.lessonTypeID = lesson.lessonTypeID;
            changingLesson.LessonTypeReference = lesson.LessonTypeReference;
            changingLesson.periodicity = lesson.periodicity;
            changingLesson.periodicityMask = lesson.periodicityMask;
            changingLesson.Professor = lesson.Professor;
            changingLesson.professorID = lesson.professorID;
            changingLesson.ProfessorReference = lesson.ProfessorReference;
            changingLesson.semester = lesson.semester;
            changingLesson.Subject = lesson.Subject;
            changingLesson.subjectID = lesson.subjectID;
            changingLesson.SubjectReference = lesson.SubjectReference;
            changingLesson.weekDay = lesson.weekDay;
            //Save Changes in database
            entityModel.SaveChanges();
        }


        #endregion
    }
}